Imports System.IO
Imports System.Drawing
Imports System.Data.SqlClient
Imports System.Web.UI
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Threading

Imports DotNetNuke
Imports DotNetNuke.Common
Imports DotNetNuke.Common.Utilities
Imports DotNetNuke.Common.Utilities.UrlUtils
Imports DotNetNuke.Data
Imports DotNetNuke.Entities.Modules
Imports DotNetNuke.Security.Roles
Imports DotNetNuke.Services.Exceptions
Imports DotNetNuke.Services.Localization
Imports DotNetNuke.Entities.Modules.Communications

Imports Microsoft.VisualBasic


Namespace TressleWorks.Modules.ThermoChart

    Partial Class ThermoChartView
        Inherits Entities.Modules.PortalModuleBase
        Implements Entities.Modules.IActionable
        Implements Entities.Modules.Communications.IModuleListener

        Dim oInfo As ThermoChartInfo
        Dim sChartsSubDir As String
        Dim oSubstitutionValues As Hashtable

        Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            oInfo = New ThermoChartInfo(Me)
            Call oInfo.Load()

            oSubstitutionValues = New Hashtable

        End Sub

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

          
            If oInfo.IsNewChart Then
                pnlChart.Visible = False

                'Dim sMsg As String = Localization.GetString("SelectionIncomplete.Message", Me.LocalResourceFile)
                'If sMsg.Length = 0 Then
                lblMessage.Text = "Selection criteria incomplete - Please edit ThermoChart Setting to complete"
                'Else
                '   lblMessage.Text = sMsg
                'End If
                lblMessage.Visible = True
                pnlMessage.Visible = True

                Exit Sub
            End If

            If IsNumeric(Request.QueryString("MIN")) Then oInfo.MinValue = Request.QueryString("MIN")
            If IsNumeric(Request.QueryString("MAX")) Then oInfo.MaxValue = Request.QueryString("MAX")
            If IsNumeric(Request.QueryString("CV")) Then oInfo.CurrentValue = Request.QueryString("CV")
            If IsNumeric(Request.QueryString("T")) Then oInfo.Title = Request.QueryString("T")
            If IsNumeric(Request.QueryString("VT")) Then oInfo.ValueFormat = Request.QueryString("VT")

            Call BuildCharts(oInfo)

        End Sub

        Public Sub OnModuleComm(ByVal s As Object, ByVal e As ModuleCommunicationEventArgs) Implements IModuleListener.OnModuleCommunication

            Select Case e.Type
                Case "SGSV_Selections"

                    Call AddParentValues(e.Value)

                    For Each sKey As String In oSubstitutionValues.Keys
                        If sKey.ToUpper = oInfo.IMCParameterName.ToUpper Then
                            oInfo.CurrentValue = Val(oSubstitutionValues(sKey))
                            Exit For
                        End If
                        'no parameter found so no need to build chart based on IMC
                        Exit Sub
                    Next

                    Call BuildCharts(oInfo)
                Case Else

            End Select

        End Sub

#Region "Private Routines"

        Public Sub BuildCharts(ByVal poInfo As ThermoChartInfo)

            Call DetermineChartSubDir()
            Call PurgeChartImages()

            If poInfo.EnableSQL And poInfo.EnableMatrix Then
                pnlChart.Visible = False
                pnlMatrix.Visible = True
                pnlMatrix.Controls.Add(BuildChartMatrix(poInfo))
            Else
                imgThermometer.ImageUrl = BuildChart(poInfo, 0)
            End If

            If poInfo.ShowSQLCommand And oSubstitutionValues.Count > 0 Then
                txtCommand.Text &= vbCrLf & vbCrLf & DisplaySubstitution()
                pnlCommand.Visible = True
            End If

            If poInfo.Header.Length > 0 Then
                Dim sHeader As String = poInfo.SubstituteParms(poInfo.Header)
                pnlHeader.Controls.Add(New LiteralControl(sHeader))
                pnlHeader.Visible = True
            End If
            If poInfo.Footer.Length > 0 Then
                Dim sFooter As String = poInfo.SubstituteParms(poInfo.Footer)
                pnlFooter.Controls.Add(New LiteralControl(sFooter))
                pnlFooter.Visible = True
            End If

        End Sub

        Public Function BuildChart(ByVal poInfo As ThermoChartInfo, ByVal piChartNum As Integer) As String

            Dim sFilename As String = String.Empty

            sFilename = Me.TemplateSourceDirectory & sChartsSubDir & DetermineFileName("_Chart.png", piChartNum)
            poInfo.Filename = Context.Server.MapPath(sFilename)

            'Call AddMessage("File: " & sFilename)

            If poInfo.EnableSQL And Not poInfo.EnableMatrix Then
                If Not GetSQLValues(poInfo) Then
                    Return String.Empty
                End If
            End If

            Dim oThermometer As New Thermometer
            Call oThermometer.ShowThermometer(poInfo)

            Return sFilename
        End Function

        Private Function BuildChartMatrix(ByVal poInfo As ThermoChartInfo) As Control
            Dim oDT As DataTable
            Dim oTable As New Table
            Dim oTableRow = New TableRow

            Dim iRow As Integer = 0
            Dim iCol As Integer = 0
            Dim iChart As Integer = 0

            Try
                oDT = GetData(poInfo, ApplySubstitutions(poInfo.SQLCommand))
                If oDT Is Nothing Then
                    Return New LiteralControl("Error building Matrix")
                End If

                If oDT.Rows.Count = 0 Then
                    Dim sMsg As String = "No Rows returned from Query"
                    Call AddMessage(sMsg)
                    Return New LiteralControl(sMsg)
                End If

                oTable.CssClass = "ThermoChartMatrix"

                For Each oRow As DataRow In oDT.Rows
                    iRow += 1
                    If poInfo.MatrixRows > 0 AndAlso iRow > poInfo.MatrixRows Then
                        Exit For
                    End If

                    iCol += 1
                    If poInfo.MatrixColumns > 0 AndAlso iCol > poInfo.MatrixColumns Then
                        'Start a new row
                        oTable.Controls.Add(oTableRow)
                        oTableRow = New TableRow
                        iCol = 1
                    End If

                    Dim oTableCell = New TableCell
                    Dim oImg As New HtmlImage

                    Call ExtractFields(oRow, poInfo)

                    iChart += 1
                    oImg.Src = BuildChart(poInfo, iChart)
                    oImg.Alt = "Chart " & iChart.ToString

                    oTableCell.controls.Add(oImg)
                    oTableRow.controls.add(oTableCell)

                Next

                If oTableRow.controls.count > 0 Then
                    oTable.Controls.Add(oTableRow)
                End If

            Catch ex As Exception
                Call AddMessage(ex.Message)
            End Try
            
            Return oTable

        End Function

        Private Function GetSQLValues(ByVal poInfo As ThermoChartInfo) As Boolean
            Dim oDT As DataTable

            Try
                oDT = GetData(poInfo, ApplySubstitutions(poInfo.SQLCommand))
                If oDT Is Nothing Then
                    Return False
                End If

                If oDT.Rows.Count = 0 Then
                    Call AddMessage("No Rows returned from Query")
                    Return False
                End If

                Dim oRow As DataRow = oDT.Rows(0)
                Call ExtractFields(oRow, poInfo)

                oDT.Dispose()

            Catch ex As Exception
                Call AddMessage(ex.Message)
            End Try
            
            Return True
        End Function

        Public Function ExtractFields(ByVal poRow As DataRow, ByVal poInfo As ThermoChartInfo) As Boolean

            Dim oDT As DataTable = poRow.Table

            Dim sField As String = String.Empty

            sField = "MaxValue"
            If oDT.Columns.Contains(sField) Then
                If Not IsDBNull(poRow(sField)) Then
                    poInfo.MaxValue = Val(poRow(sField))
                End If
            End If

            sField = "MinValue"
            If oDT.Columns.Contains(sField) Then
                If Not IsDBNull(poRow(sField)) Then
                    poInfo.MinValue = Val(poRow(sField))
                End If
            End If

            sField = "CurrentValue"
            If oDT.Columns.Contains(sField) Then
                If Not IsDBNull(poRow(sField)) Then
                    poInfo.CurrentValue = Val(poRow(sField))
                    'Call AddMessage("Current Value = " & poInfo.CurrentValue.ToString)
                End If
            End If

            sField = "Title"
            If oDT.Columns.Contains(sField) Then
                If Not IsDBNull(poRow(sField)) Then
                    poInfo.Title = poRow(sField)
                End If
            End If

            Return True
        End Function

        Private Function ApplySubstitutions(ByVal psText As String) As String

            If psText.IndexOf("[") < 0 AndAlso psText.IndexOf("<") < 0 Then
                Return psText
            End If

            Dim sResult As String = psText

            sResult = Replace(sResult, "[DNN:PortalID]", PortalId.ToString, , , Microsoft.VisualBasic.CompareMethod.Text)
            sResult = Replace(sResult, "[DNN:ModuleID]", ModuleId.ToString, , , Microsoft.VisualBasic.CompareMethod.Text)
            sResult = Replace(sResult, "[DNN:TabID]", TabId.ToString, , , Microsoft.VisualBasic.CompareMethod.Text)
            sResult = Replace(sResult, "[DNN:UserID]", UserId.ToString, , , Microsoft.VisualBasic.CompareMethod.Text)

            sResult = Replace(sResult, "<CRLF>", vbCrLf, , , Microsoft.VisualBasic.CompareMethod.Text)
            sResult = Replace(sResult, "[CRLF]", vbCrLf, , , Microsoft.VisualBasic.CompareMethod.Text)

            sResult = SubStituteParmValues(sResult)
            'sResult = SubStitutions.SubStituteDates(sResult)
            'sResult = SubStituteQuery(sResult)
            'sResult = SubStituteModuleData(sResult)

            Return sResult

        End Function

        Private Function SubStituteParmValues(ByVal psText As String) As String
            Dim sKey As String
            Dim sValue As String

            'All ParmValues will start with "[" so check if command has any - if not then exit
            If psText.IndexOf("[") < 0 Then
                Return psText
            End If

            'check if there are any ParmValues to Substitute
            If oSubstitutionValues.Count = 0 Then
                Return psText
            End If

            Dim myEnumerator As IDictionaryEnumerator = oSubstitutionValues.GetEnumerator
            While myEnumerator.MoveNext()
                sKey = myEnumerator.Key
                sValue = myEnumerator.Value
                psText = Replace(psText, sKey, sValue, , , Microsoft.VisualBasic.CompareMethod.Text)
            End While

            Return psText
        End Function

        Private Function DisplaySubstitution() As String
            Dim sbResult As New StringBuilder
            Dim sKey As String
            Dim sValue As String

            If oSubstitutionValues.Count = 0 Then
                Return String.Empty
            End If

            sbResult.AppendLine("Parameter Substitutions:")

            Dim myEnumerator As IDictionaryEnumerator = oSubstitutionValues.GetEnumerator
            While myEnumerator.MoveNext()
                sKey = myEnumerator.Key
                sValue = myEnumerator.Value
                sbResult.AppendLine("  " & sKey & " = " & sValue)
            End While

            Return sbResult.ToString
        End Function

#End Region


#Region "Data Routines"
        Private Function GetData(ByVal poInfo As ThermoChartInfo, ByVal psSQL As String) As DataTable
            Dim sErrorMessage As String
            Dim sConnection As String
            Dim iTimeout As Integer = 60

            If poInfo.ShowSQLCommand Then
                pnlCommand.Visible = True
                txtCommand.Text = psSQL
            End If

            sConnection = ResolveConnectionString(poInfo.ConnectionString)
            If sConnection.StartsWith("ERROR:") Then
                sErrorMessage = sConnection
                psSQL = String.Empty            'clear as not a problem with SQL statement
                Throw New System.Exception(sErrorMessage)
            End If

            'Dim psSQL As String
            Dim ds As New DataSet

            Try
                Dim oConnection As New SqlConnection(sConnection)
                Dim oCommand As SqlCommand

                oCommand = New SqlCommand(psSQL, oConnection)
                oCommand.CommandTimeout = iTimeout

                oConnection.Open()

                Dim oAdapter As New SqlDataAdapter(oCommand)

                Call oAdapter.Fill(ds)

                oConnection.Close()

            Catch ex As Exception

                Throw New System.Exception("GetData: " + ex.Message + vbCrLf + psSQL)

                Return Nothing

            End Try

            If poInfo.ShowSQLCommand Then
                txtCommand.Text &= vbCrLf & vbCrLf & "-- " & ds.Tables(0).Rows.Count & " Rows returned from command"
            End If

            Return ds.Tables(0)

        End Function

        Public Function ResolveConnectionString(ByVal ConnectionString As String) As String
            If ConnectionString = "" Then
                Return DotNetNuke.Common.Utilities.Config.GetConnectionString()
            Else
                If ConnectionString.StartsWith("@") And ConnectionString.Length > 2 Then
                    Dim sKey As String = ConnectionString.Substring(1)
                    Dim sAppSetting As String

                    sAppSetting = System.Configuration.ConfigurationManager.AppSettings(sKey)
                    If sAppSetting Is Nothing Then
                        Return "ERROR: Connection String contains a reference to an AppSettings (" & sKey & ") in Web Config that could not be found"
                    Else
                        Return sAppSetting
                    End If

                End If
            End If

            Return ConnectionString

        End Function

#End Region


#Region "File Routines"

        Private Sub DetermineChartSubDir()

            sChartsSubDir = "Charts"        'default

            Try
                Dim stemp As String = Localization.GetString("ChartSubDir.Config", Me.LocalResourceFile)
                If stemp.Length > 0 Then
                    sChartsSubDir = stemp
                End If

            Catch ex As Exception
                'DO Nothing... uses the default.
            End Try

            If Not sChartsSubDir.StartsWith("\") Then
                sChartsSubDir = "\" + sChartsSubDir
            End If

            If Not sChartsSubDir.EndsWith("\") Then
                sChartsSubDir += "\"
            End If

        End Sub

        Public Function DetermineFileName(ByVal psExtension As String, ByVal piChartNum As Integer, _
                                            Optional ByVal bAddUser As Boolean = True, _
                                            Optional ByVal bAddChartNum As Boolean = True, _
                                            Optional ByVal bAddUnique As Boolean = True) As String

            Dim sPattern As String = String.Format("TC_t{0}m{1}", TabModuleId, ModuleId)

            If bAddChartNum Then
                sPattern &= "c" + piChartNum.ToString
            End If

            If bAddUser Then
                If UserId > -1 Then
                    sPattern &= "u" + UserId.ToString
                Else
                    bAddUnique = True
                End If
            End If

            If bAddUnique Then
                Dim iValue As Integer = 0
                Dim sIP As String = Me.Page.Request.UserHostAddress
                If sIP.Length > 0 AndAlso sIP.Contains(".") Then
                    Dim sOctets() As String = sIP.Split(".")
                    If sOctets.Length > 3 Then
                        iValue = Val(sOctets(2)) * 1000 + Val(sOctets(3))
                    End If
                End If
                If Not (bAddChartNum And bAddUser) Then
                    sPattern &= "*"
                End If

                sPattern &= "a" & iValue.ToString
            End If

            If Not psExtension.StartsWith("*") Then
                Dim iRnd As Long = Now.Subtract(DateTime.Today).TotalMilliseconds
                sPattern &= "x" & Hex(iRnd)
            End If

            Return sPattern + psExtension

        End Function

        Public Sub PurgeChartImages()
            Dim sPath As String
            Dim sFileList As String()
            Dim sStaticImageFilename As String = String.Empty

            Dim sPattern As String = DetermineFileName("*.png", 0, False, False, True)

            sPath = TemplateSourceDirectory + sChartsSubDir
            sPath = Context.Server.MapPath(sPath)

            'Call AddMessage("Path=" & sPath)
            'Call AddMessage("Pattern=" & sPattern)

            sFileList = Directory.GetFiles(sPath, sPattern)
            'Call AddMessage("Found=" & sFileList.Length)

            For Each sFile As String In sFileList

                'Debug.WriteLine("Delete " & sFile)
                'Call AddMessage("Deleting " & sFile)
                File.Delete(sFile)
            Next

            Thread.Sleep(50)    'allow OS to refresh directory prior to creating new

        End Sub

        Private Function GetChartImages() As String()
            Dim sFileList As String()

            Dim sPattern As String
            'If oChartInfo.ExportToPDF Then
            '    sPattern = DetermineFileName("*.jpg", False)
            'Else
            sPattern = DetermineFileName("*.png", False)
            'End If

            sFileList = Directory.GetFiles(Context.Server.MapPath(Me.TemplateSourceDirectory), sPattern)
            If sFileList.Length > 0 Then
                Return sFileList
            Else
                Return Nothing
            End If

        End Function

        Private Function GetChartDocuments() As String()
            Dim sFileList As String()

            Dim sPattern As String = DetermineFileName("*.pdf", True)

            sFileList = Directory.GetFiles(Context.Server.MapPath(Me.TemplateSourceDirectory), sPattern)
            If sFileList.Length > 0 Then
                Return sFileList
            Else
                Return Nothing
            End If

        End Function

        Private Function ExpandFilename(ByVal psFileName As String) As String
            Dim sPath As String = String.Empty

            If psFileName.IndexOf("/") < 0 AndAlso psFileName.IndexOf("\") Then
                Return Me.TemplateSourceDirectory & "\" & psFileName
            End If

            sPath = Context.Server.MapPath(psFileName)

            Return String.Empty
        End Function

        Public Sub AddParentValues(ByVal oParentValues As Hashtable)
            Dim sKey As String
            Dim sValue As String

            If oParentValues.Count = 0 Then Exit Sub
            If oSubstitutionValues Is Nothing Then
                oSubstitutionValues = New Hashtable
            End If

            Dim myEnumerator As IDictionaryEnumerator = oParentValues.GetEnumerator
            While myEnumerator.MoveNext()
                sKey = myEnumerator.Key.replace("[", "[Parent_")
                sValue = myEnumerator.Value
                If Not oSubstitutionValues.ContainsKey(sKey) Then
                    oSubstitutionValues.Add(sKey, sValue)
                End If
            End While

        End Sub

        Private Sub AddMessage(ByVal psText As String)
            pnlMessage.Visible = True
            lblMessage.Visible = True
            If lblMessage.Text.Length > 0 Then
                lblMessage.Text &= "<br>"
            End If
            lblMessage.Text &= psText
        End Sub

#End Region

#Region "Optional Interfaces"

        Public ReadOnly Property ModuleActions() As Entities.Modules.Actions.ModuleActionCollection Implements Entities.Modules.IActionable.ModuleActions
            Get
                Dim Actions As New Entities.Modules.Actions.ModuleActionCollection
                Dim sAction As String

                sAction = Localization.GetString(Entities.Modules.Actions.ModuleActionType.AddContent, LocalResourceFile)
                Actions.Add(GetNextActionID, sAction, Entities.Modules.Actions.ModuleActionType.AddContent, "", "", EditUrl(), False, DotNetNuke.Security.SecurityAccessLevel.Edit, True, False)

                Return Actions
            End Get
        End Property

#End Region


    End Class
End Namespace
